/*
 * Created on 2005-3-6
 *
 */
package bma.common.langutil.convert;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import bma.common.langutil.convert.common.CommonConverter;
import bma.common.langutil.core.ClassUtil;
import bma.common.langutil.core.ExceptionUtil;
import bma.common.langutil.core.ObjectUtil;

/**
 * @author guanzhong
 * @since 1.0 (imported from BMA.ESP Project)
 */
public class ConvertManager {

	private static ConvertManager instance = new ConvertManager();

	public static ConvertManager getInstance() {
		return instance;
	}

	protected List<Converter> converters = new CopyOnWriteArrayList<Converter>();

	public List<Converter> getConverters() {
		return converters;
	}

	public void setConverters(List<Converter> converters) {
		this.converters = converters;
	}

	public boolean has(Class cls) {
		for (Converter old : converters) {
			if (ObjectUtil.equals(old.getClass(), cls)) {
				return true;
			}
		}
		return false;
	}

	public boolean add(Converter c) {
		if (converters.contains(c))
			return false;
		converters.add(c);
		return true;
	}

	public boolean remove(Converter c) {
		return converters.remove(c);
	}

	public boolean canCast(Object obj, Class<?> to) {
		if (obj == null)
			return false;
		if (to == null)
			return false;
		if (to.isInstance(obj))
			return true;
		if (obj instanceof Convertable) {
			Convertable ca = (Convertable) obj;
			if (ca.canConvert(to))
				return true;
		}
		return canCast(obj.getClass(), to);
	}

	public boolean canCast(Class<?> from, Class<?> to) {

		if (from == null)
			return false;

		if (to == null)
			return false;

		if (ClassUtil.isAssignFrom(to, from))
			return true;

		if (from == String.class && to.isEnum()) {
			return true;
		}
		if (from.isEnum() && to == String.class) {
			return true;
		}

		try {
			if (CommonConverter.doCanConvert(from, to)) {
				return true;
			}

			for (Converter c : converters) {
				if (c.canConvert(from, to)) {
					return true;
				}
			}

			return false;
		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public <TYPE> TYPE cast(Object src, Class<TYPE> to) {
		Object r = cast(src, to);
		return ClassUtil.cast(to, r);
	}

	@SuppressWarnings("unchecked")
	public Object convert(Object src, Class<?> to) {
		if (src == null)
			return null;

		Class<?> from = src.getClass();
		if (to == null)
			return src;

		if (to.isInstance(src))
			return to.cast(src);

		if (src instanceof Convertable) {
			Convertable ca = (Convertable) src;
			if (ca.canConvert(to))
				return ca.convertTo(to);
		}

		if (from == String.class && to.isEnum()) {
			Class<? extends Enum> cls = to.asSubclass(Enum.class);
			Enum valueOf = Enum.valueOf(cls, (String) src);
			return valueOf;
		}
		if (from.isEnum() && to == String.class) {
			return ((Enum) src).name();
		}

		try {
			if (CommonConverter.doCanConvert(from, to)) {
				try {
					return CommonConverter.doConvertTo(src, to);
				} catch (Exception e) {
					return null;
				}
			}

			for (Converter c : converters) {
				if (c.canConvert(from, to)) {
					return c.convertTo(src, to);
				}
			}

			return null;
		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}

	}

	/**
	 * 判断是否2个类型是指定的2个类型
	 * 
	 * @param test1
	 * @param test2
	 * @param want1
	 * @param want2
	 * @return
	 */
	public static boolean isType(Class test1, Class test2, Class want1,
			Class want2) {
		if (ClassUtil.isExtendFrom(test1, want1)) {
			return ClassUtil.isExtendFrom(test2, want2);
		} else if (ClassUtil.isExtendFrom(test2, want1)) {
			return ClassUtil.isExtendFrom(test1, want2);
		}
		return false;
	}

}